#include <iostream>
#include <string>

using namespace std;

// demo 1: array
template <typename T, size_t N>
constexpr size_t array_size(const T (&a)[N])
{
    return N;
}

template <typename T, size_t N>
void print(const T (&a)[N])
{
    for (size_t i = 0; i < N; ++i)
    {
        cout << a[i] << " ";
    }
    cout << endl;
}

template <typename T, size_t N>
const T *mybegin(const T (&a)[N])
{
    return &a[0];
}

template <typename T, size_t N>
const T *myend(const T (&a)[N])
{
    return &a[0] + N;
}

// demo2: iterator
template <typename T, typename I>
I find(I begin, I end, const T &value)
{
    while (begin != end && *begin != value)
    {
        ++begin;
    }
    return begin;
}

// demo3: class
template <typename T>
class MyClass
{
public:
    MyClass(T v) : value(v) {}
    T get() const { return value; }

private:
    T value;
};

int main()
{
    int a[5] = {1, 2, 3, 4, 5};
    print(a);

    cout << "size of a: " << array_size(a) << endl;

    for (auto i = mybegin(a); i != myend(a); ++i)
    {
        cout << *i << " ";
    }
    cout << endl;

    // demo3: class
    MyClass<int> mci(42.2);
    cout << "mc.get(): " << mci.get() << endl;
    MyClass<double> mcd(42.2);
    cout << "mc.get(): " << mcd.get() << endl;

    return 0;
}